#include <jni.h>
#include <string>
#include "./../jni/exfat/fuse/methodheader.h"

//int getstate();


extern "C" JNIEXPORT jstring JNICALL
Java_com_example_testexfatwrite_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++ aaa";
    return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT jint JNICALL Java_com_example_testexfatwrite_myndk_getstate(JNIEnv *env, jobject objects){
    return mount_exfat_main_test();
}

//#include <string>
//#include "com_example_myapplication_myndk.h"
//#define FUSE_USE_VERSION 26
//#include "./../jni/fuse/include/fuse.h"
//#include <errno.h>
//#include <fcntl.h>
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include "./../jni/exfat/libexfat/exfat.h"
//#include <inttypes.h>
//#include <limits.h>
//#include <sys/types.h>
//#include <pwd.h>
//#include <unistd.h>
//
//#ifndef DEBUG
//#define exfat_debug(format, ...)
//#endif
//
//#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
//#error FUSE 2.6 or later is required
//#endif
//
//const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
//                              "default_permissions";
//
//struct exfat ef;
//
//static struct exfat_node* get_node(const struct fuse_file_info* fi)
//{
//    return (struct exfat_node*) (size_t) fi->fh;
//}
//
//static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
//{
//    fi->fh = (uint64_t) (size_t) node;
//}
//
//static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
//{
//    struct exfat_node* node;
//    int rc;
//
//    exfat_debug("[%s] %s", __func__, path);
//
//    rc = exfat_lookup(&ef, &node, path);
//    if (rc != 0)
//        return rc;
//
//    exfat_stat(&ef, node, stbuf);
//    exfat_put_node(&ef, node);
//    return 0;
//}
//
//static int fuse_exfat_truncate(const char* path, off64_t size)
//{
//    struct exfat_node* node;
//    int rc;
//
//    //exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
//
//    rc = exfat_lookup(&ef, &node, path);
//    if (rc != 0)
//        return rc;
//
//    exfat_dirty(&ef, true);
//    rc = exfat_truncate(&ef, node, size, true);
//    if (rc != 0)
//    {
//        exfat_flush_node(&ef, node);	/* ignore return code */
//        exfat_put_node(&ef, node);
//        return rc;
//    }
//    rc = exfat_flush_node(&ef, node);
//    exfat_put_node(&ef, node);
//    return rc;
//}
//
//static int fuse_exfat_readdir(const char* path, void* buffer,
//                              fuse_fill_dir_t filler, off64_t offset, struct fuse_file_info* fi)
//{
//    struct exfat_node* parent;
//    struct exfat_node* node;
//    struct exfat_iterator it;
//    int rc;
//    char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
//
//    exfat_debug("[%s] %s", __func__, path);
//
//    rc = exfat_lookup(&ef, &parent, path);
//    if (rc != 0)
//        return rc;
//    if (!(parent->flags & EXFAT_ATTRIB_DIR))
//    {
//        exfat_put_node(&ef, parent);
//        exfat_error("'%s' is not a directory (0x%x)", path, parent->flags);
//        return -ENOTDIR;
//    }
//
//    filler(buffer, ".", NULL, 0);
//    filler(buffer, "..", NULL, 0);
//
//    rc = exfat_opendir(&ef, parent, &it);
//    if (rc != 0)
//    {
//        exfat_put_node(&ef, parent);
//        exfat_error("failed to open directory '%s'", path);
//        return rc;
//    }
//    while ((node = exfat_readdir(&ef, &it)))
//    {
//        exfat_get_name(node, name, sizeof(name) - 1);
//        exfat_debug("[%s] %s: %s, %" PRId64" bytes, cluster 0x%x", __func__,
//                    name, IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
//                    node->size, node->start_cluster);
//        filler(buffer, name, NULL, 0);
//        exfat_put_node(&ef, node);
//    }
//    exfat_closedir(&ef, &it);
//    exfat_put_node(&ef, parent);
//    return 0;
//}
//
//static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
//{
//    struct exfat_node* node;
//    int rc;
//
//    exfat_debug("[%s] %s", __func__, path);
//
//    rc = exfat_lookup(&ef, &node, path);
//    if (rc != 0)
//        return rc;
//    set_node(fi, node);
//    fi->keep_cache = 1;
//    return 0;
//}
//
//static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
//{
//    /*
//       This handler is called by FUSE on close() syscall. If the FUSE
//       implementation does not call flush handler, we will flush node here.
//       But in this case we will not be able to return an error to the caller.
//       See fuse_exfat_flush() below.
//    */
//    exfat_debug("[%s] %s", __func__, path);
//    exfat_flush_node(&ef, get_node(fi));
//    exfat_put_node(&ef, get_node(fi));
//    return 0; /* FUSE ignores this return value */
//}
//
//static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
//{
//    /*
//       This handler may be called by FUSE on close() syscall. FUSE also deals
//       with removals of open files, so we don't free clusters on close but
//       only on rmdir and unlink. If the FUSE implementation does not call this
//       handler we will flush node on release. See fuse_exfat_relase() above.
//    */
//    exfat_debug("[%s] %s", __func__, path);
//    return exfat_flush_node(&ef, get_node(fi));
//}
//
//static int fuse_exfat_fsync(const char* path, int datasync,
//                            struct fuse_file_info *fi)
//{
//    int rc;
//
//    exfat_debug("[%s] %s", __func__, path);
//    rc = exfat_flush(&ef);
//    if (rc != 0)
//        return rc;
//    return exfat_sync(&ef);
//}
//
//static int fuse_exfat_read(const char* path, char* buffer, size_t size,
//                           off64_t offset, struct fuse_file_info* fi)
//{
//    ssize_t ret;
//    struct exfat_node* node;
//
//    exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
//    node = get_node(fi);
//    ret = exfat_generic_pread(&ef, node, buffer, size, offset);
//    if (ret < 0)
//        return -EIO;
//#if !defined(ALWAYS_USE_SYNC_OPTION) || !ALWAYS_USE_SYNC_OPTION
//    if ( ef.sync )
//#endif
//    {
//        if ( !ef.ro && ef.noatime && (node->flags & EXFAT_ATTRIB_DIRTY) != 0 )
//            exfat_flush_node(&ef, node);
//    }
//    return ret;
//}
//
//static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
//                            off64_t offset, struct fuse_file_info* fi)
//{
//    struct exfat_node* node = get_node(fi);
//    exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
//    exfat_dirty(&ef, true);
//
//    uint32_t c1 = exfat_bytes2clusters(&ef, node->size);
//    ssize_t ret = exfat_generic_pwrite(&ef, node, buffer, size, offset);
//    uint32_t c2 = exfat_bytes2clusters(&ef, node->size);
//
//    if (ret < 0)
//        return -EIO;
//
//#if !defined(ALWAYS_USE_SYNC_OPTION) || !ALWAYS_USE_SYNC_OPTION
//    if ( ef.sync )
//#endif
//    {
//        if ( c1 != c2 )
//        {
//            // Keep FAT, free clusters map and metadata consistent,
//            // but don't close the volume, and don't sync!
//            // Here we sacrifice the consistency for the sake of write performance :(
//            // But we may end up with inconsistent cmap/FAT/metadata only on power loss
//            // or card removal during the long write.
//            ef.in_write = true;
//            int rc = exfat_flush_node(&ef, node);
//            ef.in_write = false;
//            if ( rc != 0 )
//                return -1;
//        }
//        ef.bytes_written += ret;
//        if ( (offset < 1024*1024 && c1 != c2) // every new cluster for small files, or at the file beginning
//             || (offset < 16*1024*1024 && ef.bytes_written >= 2*1024*1024)
//             || (offset < 32*1024*1024 && ef.bytes_written >= 8*1024*1024)
//                )
//        {
//            // Sync every so many bytes written, but not for files >32 MB.
//            exfat_sync(&ef);
//        }
//    }
//    return ret;
//}
//
//static int fuse_exfat_unlink(const char* path)
//{
//    struct exfat_node* node;
//    int rc;
//
//    exfat_debug("[%s] %s", __func__, path);
//
//    rc = exfat_lookup(&ef, &node, path);
//    if (rc != 0)
//        return rc;
//
//    exfat_dirty(&ef, true);
//    rc = exfat_unlink(&ef, node);
//    exfat_put_node(&ef, node);
//    if (rc == 0)
//        rc = exfat_cleanup_node(&ef, node);
//    exfat_dirty(&ef, false);
//    return rc;
//}
//
//static int fuse_exfat_rmdir(const char* path)
//{
//    struct exfat_node* node;
//    int rc;
//
//    exfat_debug("[%s] %s", __func__, path);
//
//    rc = exfat_lookup(&ef, &node, path);
//    if (rc != 0)
//        return rc;
//
//    exfat_dirty(&ef, true);
//    rc = exfat_rmdir(&ef, node);
//    exfat_put_node(&ef, node);
//    if (rc == 0)
//        rc = exfat_cleanup_node(&ef, node);
//    exfat_dirty(&ef, false);
//    return rc;
//}
//
//static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
//{
//    int rc;
//    exfat_debug("[%s] %s 0%ho", __func__, path, mode);
//    exfat_dirty(&ef, true);
//    rc = exfat_mknod(&ef, path);
//    exfat_dirty(&ef, false);
//    return rc;
//}
//
//static int fuse_exfat_mkdir(const char* path, mode_t mode)
//{
//    int rc;
//    exfat_debug("[%s] %s 0%ho", __func__, path, mode);
//    exfat_dirty(&ef, true);
//    rc = exfat_mkdir(&ef, path);
//    exfat_dirty(&ef, false);
//    return rc;
//}
//
//static int fuse_exfat_rename(const char* old_path, const char* new_path)
//{
//    int rc;
//    exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
//    exfat_dirty(&ef, true);
//    rc = exfat_rename(&ef, old_path, new_path);
//    exfat_dirty(&ef, false);
//    return rc;
//}
//
//static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
//{
//    struct exfat_node* node;
//    int rc;
//
//    exfat_debug("[%s] %s", __func__, path);
//
//    rc = exfat_lookup(&ef, &node, path);
//    if (rc != 0)
//        return rc;
//
//    exfat_utimes(node, tv);
//    rc = exfat_flush_node(&ef, node);
//    exfat_put_node(&ef, node);
//    return rc;
//}
//
//static int fuse_exfat_chmod(const char* path, mode_t mode)
//{
//    const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
//                                   S_IRWXU | S_IRWXG | S_IRWXO;
//
//    exfat_debug("[%s] %s 0%ho", __func__, path, mode);
//    if (mode & ~VALID_MODE_MASK)
//        return -EPERM;
//    return 0;
//}
//
//static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
//{
//    exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
//    if (uid != ef.uid || gid != ef.gid)
//        return -EPERM;
//    return 0;
//}
//
//static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
//{
//    exfat_debug("[%s]", __func__);
//
//    sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
//    sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
//    sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
//    sfs->f_bavail = exfat_count_free_clusters(&ef);
//    sfs->f_bfree = sfs->f_bavail;
//    sfs->f_namemax = EXFAT_NAME_MAX;
//
//    /*
//       Below are fake values because in exFAT there is
//       a) no simple way to count files;
//       b) no such thing as inode;
//       So here we assume that inode = cluster.
//    */
//    sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
//    sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
//    sfs->f_ffree = sfs->f_bavail;
//
//    return 0;
//}
//
//static void* fuse_exfat_init(struct fuse_conn_info* fci)
//{
//    exfat_debug("[%s]", __func__);
//#ifdef FUSE_CAP_BIG_WRITES
//    fci->want |= FUSE_CAP_BIG_WRITES;
//#endif
//    return NULL;
//}
//
//static void fuse_exfat_destroy(void* unused)
//{
//    exfat_debug("[%s]", __func__);
//    exfat_unmount(&ef);
//}
//
//static void usage(const char* prog)
//{
//    fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
//    exit(1);
//}
//
//static struct fuse_operations fuse_exfat_ops =
//        {
//                .getattr  = fuse_exfat_getattr,
//                .truncate = fuse_exfat_truncate,
//                .readdir  = fuse_exfat_readdir,
//                .open     = fuse_exfat_open,
//                .release  = fuse_exfat_release,
//                .flush    = fuse_exfat_flush,
//                .fsync    = fuse_exfat_fsync,
//                .fsyncdir = fuse_exfat_fsync,
//                .read     = fuse_exfat_read,
//                .write    = fuse_exfat_write,
//                .unlink   = fuse_exfat_unlink,
//                .rmdir    = fuse_exfat_rmdir,
//                .mknod    = fuse_exfat_mknod,
//                .mkdir    = fuse_exfat_mkdir,
//                .rename   = fuse_exfat_rename,
//                .utimens  = fuse_exfat_utimens,
//                .chmod    = fuse_exfat_chmod,
//                .chown    = fuse_exfat_chown,
//                .statfs   = fuse_exfat_statfs,
//                .init     = fuse_exfat_init,
//                .destroy  = fuse_exfat_destroy,
//        };
//
//static char* add_option(char* options, const char* name, const char* value)
//{
//    size_t size;
//    char* optionsf = options;
//
//    if (value)
//        size = strlen(options) + strlen(name) + strlen(value) + 3;
//    else
//        size = strlen(options) + strlen(name) + 2;
//
//    options = static_cast<char *>(realloc(options, size));
//    if (options == NULL)
//    {
//        free(optionsf);
//        exfat_error("failed to reallocate options string");
//        return NULL;
//    }
//    strcat(options, ",");
//    strcat(options, name);
//    if (value)
//    {
//        strcat(options, "=");
//        strcat(options, value);
//    }
//    return options;
//}
//
//static char* add_user_option(char* options)
//{
//    struct passwd* pw;
//
//    if (getuid() == 0)
//        return options;
//
//    pw = getpwuid(getuid());
//    if (pw == NULL || pw->pw_name == NULL)
//    {
//        free(options);
//        exfat_error("failed to determine username");
//        return NULL;
//    }
//    return add_option(options, "user", pw->pw_name);
//}
//
//static char* add_blksize_option(char* options, long cluster_size)
//{
//    long page_size = sysconf(_SC_PAGESIZE);
//    char blksize[20];
//
//    if (page_size < 1)
//        page_size = 0x1000;
//
//    snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
//    return add_option(options, "blksize", blksize);
//}
//
//static char* add_fuse_options(char* options, const char* spec)
//{
//    options = add_option(options, "fsname", spec);
//    if (options == NULL)
//        return NULL;
//    options = add_user_option(options);
//    if (options == NULL)
//        return NULL;
//    options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
//    if (options == NULL)
//        return NULL;
//
//    return options;
//}
//extern "C" JNIEXPORT jint JNICALL Java_com_example_testexfatwrite_myndk_getstate(JNIEnv *env, jobject objects){
//    return getstate();
//}